/**
 * Copyright 2005 The Apache Software Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.edi.db.dialect;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.edi.db.EdiDb;
import com.edi.db.dialect.function.DialectFunction;
import com.edi.db.table.FieldEntity;
import com.edi.db.table.TableEntity;
import com.edi.db.type.NullableType;
import com.edi.db.type.TypeNames;
import com.edi.util.ReflectHelper;

public abstract class Dialect {
	private static final Log log = LogFactory.getLog(Dialect.class);

	public static final String DEFAULT_BATCH_SIZE = "15";

	public static final String NO_BATCH = "0";

	public static final String QUOTE = "'\"[";

	public static final String CLOSED_QUOTE = "`\"]";

	protected boolean ignoreCase = true;

	public boolean getIgnoreCase() {
		return this.ignoreCase;
	}

	public void setIgnoreCase(boolean ignoreCase) {
		this.ignoreCase = ignoreCase;
	}

	/**
	 * sql函数集合
	 */
	private Map functionHash = new HashMap();

	/**
	 * sql关键字结合
	 */
	private Map keyHash = new HashMap();

	/**
	 * java.sql数据类型与bullableType对应表
	 */
	private Map EdiDbTypeNames = new HashMap();

	/**
	 * 方言数据库数据类型 与java.sql.Types 中的对应
	 */
	private TypeNames typeNames = new TypeNames();

	private final Properties properties = new Properties();

	public Dialect() {
		// registKeyWords();
		// 放入标准sql函数
		registFunctions();

	}

	/**
	 * 注册函数，各方言类可以重载该方法，添加自己的方言函数
	 * 
	 */
	protected void registFunctions() {
		registFunction("substring", new CommonFunction(EdiDb.STRING,
				"substring"));
		registFunction("locate", new CommonFunction(EdiDb.INTEGER, "locate"));
		registFunction("trim", new CommonFunction(EdiDb.STRING, "trim"));
		registFunction("ltrim", new CommonFunction(EdiDb.STRING, "ltrim"));
		registFunction("rtrim", new CommonFunction(EdiDb.STRING, "rtrim"));
		registFunction("length", new CommonFunction(EdiDb.INTEGER, "length"));
		registFunction("bit_length", new CommonFunction(EdiDb.INTEGER,
				"bit_length"));
		registFunction("coalesce",
				new CommonFunction(EdiDb.INTEGER, "coalesce"));
		registFunction("nullif", new CommonFunction(EdiDb.FLOAT, "nullif"));
		registFunction("sqrt", new CommonFunction(EdiDb.BIG_INTEGER, "sqrt"));
		registFunction("upper", new CommonFunction(EdiDb.STRING, "upper"));
		registFunction("lower", new CommonFunction(EdiDb.STRING, "lower"));
		registFunction("second", new CommonFunction(EdiDb.INTEGER, "second"));
		registFunction("minute", new CommonFunction(EdiDb.INTEGER, "minute"));
		registFunction("hour", new CommonFunction(EdiDb.INTEGER, "hour"));
		registFunction("day", new CommonFunction(EdiDb.INTEGER, "day"));

		registFunction("month", new CommonFunction(EdiDb.INTEGER, "month"));

		registFunction("year", new CommonFunction(EdiDb.INTEGER, "year"));

		registFunction("abs", new CommonFunction(EdiDb.FLOAT, "abs"));

		registFunction("mod", new CommonFunction(EdiDb.FLOAT, "mod"));
		registFunction("sign", new CommonFunction(EdiDb.FLOAT, "sign"));

		registFunction("acos", new CommonFunction(EdiDb.FLOAT, "acos"));
		registFunction("asin", new CommonFunction(EdiDb.FLOAT, "asin"));
		registFunction("atan", new CommonFunction(EdiDb.FLOAT, "atan"));
		registFunction("cos", new CommonFunction(EdiDb.FLOAT, "cos"));
		registFunction("cot", new CommonFunction(EdiDb.FLOAT, "cot"));
		registFunction("exp", new CommonFunction(EdiDb.FLOAT, "exp"));
		registFunction("log", new CommonFunction(EdiDb.FLOAT, "log"));
		registFunction("log10", new CommonFunction(EdiDb.FLOAT, "log10"));
		registFunction("sin", new CommonFunction(EdiDb.FLOAT, "sin"));
		registFunction("tan", new CommonFunction(EdiDb.FLOAT, "tan"));
		registFunction("pi", new CommonFunction(EdiDb.FLOAT, "pi"));
		registFunction("square", new CommonFunction(EdiDb.FLOAT, "square"));
		registFunction("rand", new CommonFunction(EdiDb.FLOAT, "rand"));
		registFunction("radians", new CommonFunction(EdiDb.FLOAT, "radians"));
		registFunction("degrees", new CommonFunction(EdiDb.FLOAT, "degrees"));
		registFunction("round", new CommonFunction(EdiDb.FLOAT, "round"));
		registFunction("ceiling", new CommonFunction(EdiDb.FLOAT, "ceiling"));
		registFunction("isnull", new CommonFunction(EdiDb.FLOAT, "isnull"));
		registFunction("min", new CommonFunction(EdiDb.FLOAT, "min"));
		registFunction("max", new CommonFunction(EdiDb.FLOAT, "max"));
		registFunction("sum", new CommonFunction(EdiDb.FLOAT, "sum"));
		registFunction("avg", new CommonFunction(EdiDb.FLOAT, "cavg"));
		registFunction("count", new CommonFunction(EdiDb.INTEGER, "count"));
	}

	/**
	 * 注册关键字
	 * 
	 */
	protected void registKeyWords() {
		registKey("select", null);
		registKey("update", null);
		registKey("delete", null);
		registKey("insert", null);
		registKey("distinct", null);
		registKey("from", null);
		registKey("where", null);
		registKey("like", null);
		registKey("inner", null);
		registKey("outer", null);
		registKey("full", null);
		registKey("join", null);
		registKey("left", null);
		registKey("right", null);
		registKey("group", null);
		registKey("order", null);
		registKey("by", null);
		registKey("in", null);
		registKey("asc", null);
		registKey("desc", null);
		registKey("and", null);
		registKey("or", null);
		registKey("not", null);
		registKey("union", null);
	}

	public CommonFunction getFunction(String key) {
		if (functionHash.get(key) != null)
			return (CommonFunction) functionHash.get(key);
		return null;
	}

	//	
	// public static Dialect getDialect() throws Exception {
	// String dialectName = Environment.getProperties().getProperty(
	// Environment.DIALECT );
	// return instantiateDialect( dialectName );
	// }
	/**
	 * 将方言数据类别注册到java.sql.types
	 * 
	 * @param code
	 * @param name
	 */
	protected void registerColumnType(int code, int capacity, String name) {
		typeNames.put(code, capacity, name);
	}

	protected void registerColumnType(int code, String name) {
		typeNames.put(code, name);
	}

	/**
	 * 获取方言数据类别
	 * 
	 * @param code
	 * @return
	 */
	public String getTypeName(int code) throws Exception {
		String result = typeNames.get(code);
		if (result == null) {
			throw new Exception("没有找到对应的方言数据类型 " + code);
		}
		return result;
	}

	/**
	 * 获取数据库方言数据类别
	 * 
	 * @param code
	 * @param length
	 * @param precision
	 * @param scale
	 * @return
	 * @throws Exception
	 */
	public String getTypeName(int code, int length, int precision, int scale)
			throws Exception {
		String result = typeNames.get(code, length, precision, scale);
		if (result == null) {
			throw new Exception("没有找到该键值 " + code + ", 该长度: " + length);
		}
		return result;
	}

	/**
	 * 注册DB类型
	 * 
	 * @param code
	 * @param name
	 */
	protected void registerEdiDbType(int code, String name) {
		EdiDbTypeNames.put(code, name);
	}

	/**
	 * 根据键值获取方言sql中的表列数据类型
	 * 
	 * @param code
	 * @return
	 */
	public Object getEdiDbType(int code) {
		return EdiDbTypeNames.get(code);

	}

	/**
	 * 注册函数
	 * 
	 * @param key
	 * @param function
	 */
	protected void registFunction(String key, DialectFunction function) {
		functionHash.put(key, function);
	}

	protected void registKey(String key, String dialectSqlKey) {
		if (dialectSqlKey == null)
			this.keyHash.put(key, key);
		else
			this.keyHash.put(key, dialectSqlKey);
	}

	/**
	 * 根据键值获取对应方言sql关键字
	 * 
	 * @param word
	 * @return
	 */
	public String getKeyword(String word) {
		return (String) keyHash.get(word);
	}

	/**
	 * 获取全局properties
	 */
	public final Properties getDefaultProperties() {
		return properties;
	}

	public static Dialect instantiateDialect(String dialectName)
			throws Exception {
		if (dialectName == null) {
			throw new Exception("方言名称不能为空");
		}
		try {
			return (Dialect) ReflectHelper.classForName(dialectName)
					.newInstance();
		} catch (ClassNotFoundException cnfe) {
			throw new Exception("找不到类: " + dialectName);
		} catch (Exception e) {
			throw new Exception("不能构造方言类实例", e);
		}
	}

	/**
	 * 检查该表是否存在
	 * 
	 * @param tableName
	 * @return
	 */
	public abstract String ifExitTable(String tableName);
	
	public abstract List<String> getPrimaryKeys(Connection conn,String tableName)throws SQLException;

	/**
	 * 产生表
	 * 
	 * @param tableEntity
	 * @return
	 */
	public abstract String createTable(TableEntity tableEntity);
	
	public abstract NullableType getSqlType(int type,int precision,int scale);

	/**
	 * 删除列
	 * 
	 * @param tableName
	 * @param fieldList
	 * @return
	 */
	public abstract String dropColumn(String tableName, List fieldList);

	/**
	 * 添加列
	 * 
	 * @param tableName
	 * @param fieldList
	 * @return
	 */
	public abstract String addColumn(String tableName, List fieldList);

	/**
	 * 修改列
	 * 
	 * @param tableName
	 * @param fieldList
	 * @return
	 */
	public abstract String modifyColumn(String tableName, List fieldList);

	/**
	 * 翻译eql
	 * 
	 * @param eql
	 * @return
	 */
	public abstract String translate(String eql);

	/**
	 * 获取保存sql，用于批量添加提交
	 * 
	 * @param fieldNameist
	 * @param tableName
	 * @return
	 */
	public abstract String getSavePreparedString(List fieldNameist,
			String tableName);


	public abstract boolean isEqualType(NullableType type1, NullableType type2);

	/**
	 * 获取保存sql，用于批量删除
	 * 
	 * @param fieldNameist
	 * @param tableName
	 * @return
	 */
	public abstract String getDeletePreparedString(TableEntity tableEntity);

	protected List getColumnList(TableEntity tableEntity) {
		List<String> fieldNameist = new ArrayList<String>();

		Hashtable<String, FieldEntity> fields = tableEntity.getFieldEntitys();
		Set<String> fieldNames = fields.keySet();
		fieldNameist.addAll(fieldNames);

		return fieldNameist;
	}

	/**
	 * 普通函数，做简单的字符替换
	 * 
	 * @author cya
	 * 
	 */
	class CommonFunction extends DialectFunction {
		/**
		 * 函数返回值类型
		 */
		private NullableType type;

		/**
		 * 函数名称
		 */
		private String name;

		public CommonFunction(NullableType type, String name) {
			this.type = type;
			this.name = name;
		}

		public String process(String eql, String key, String function) {
			StringBuffer buffer = new StringBuffer();
			buffer.append(eql);
			int startFun = eql.indexOf(function);
			int endFun = startFun + function.length();
			function = function.replaceAll(key, this.name); // 将注册的函数名替换eql中的函数名
			buffer.replace(startFun, endFun, function);
			eql = buffer.toString();
			return eql;
		}

	}
}
